package de.tu_darmstadt.gdi1.xcom.tests.testcases.tutors;

import static org.junit.Assert.*;

import java.util.HashMap;

import org.junit.Before;
import org.junit.Test;

import de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel2;

/**
 * 
 * Tests if savegames are correctly interpreted
 * 
 * @author Lukas Schwoebel
 *
 */
public class SavegameTest {
	
	private XcomTestAdapterLevel2 testAdapter;
	
	/**
	 * @throws java.lang.Exception
	 */
	@Before
	public void setUp() throws Exception {
		testAdapter = new XcomTestAdapterLevel2();
	}
	

	private String testSaveGameLevel = "" +
		"#####\n" +
		"#...#\n" +
		"#...#\n" +
		"#m..#\n" +
		"#...#\n" +
		"#...#\n" +
		"#####\n";

	/**
	 * Test method for {@link de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel1#loadLevelFromString()}.
	 */
	@Test
	public final void testSaveGameloaded() {
		
		// load savegame
		testAdapter.loadLevelFromString(TestLevel.saveGame1);
		
		// there were two mobs that had 0 healthpoints in the savegame - they should not be in the level
		assertEquals("The player at 11:4 had 0 healthpoints in the loaded savegame - he shouldn't be in the level any more", '.',
				testAdapter.elementOnPosition(11, 4));
		assertEquals("The zombie at 18:4 had 0 healthpoints in the loaded savegame - it shouldn't be in the level any more", '.',
				testAdapter.elementOnPosition(18, 4));
		
		// there were two mobs that had 0 healthpoints in the savegame - they should not be saved in a newly created savegame
		String saveGameCreated = testAdapter.returnGamestateAsSavegame();
		
		assertFalse("The player at 11:4 had 0 healthpoints in the loaded savegame - he shouldn't be saved in a created savegame",
				(saveGameCreated.indexOf("//@;11;4;n;0;") >= 0) );
		assertFalse("The alien at 18:4 had 0 healthpoints in the loaded savegame - it shouldn't be saved in a created savegame",
				(saveGameCreated.indexOf("//Z;18;4;n;0;") >= 0) );
	}
	
	/**
	 * Test method for {@link de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel1#loadLevelFromString()}.
	 */
	@Test
	public final void testIsLostAfterSavegameLoading() {
		
		HashMap<String, Boolean> testSaveGamesLost = new HashMap<String, Boolean>();
		
		// some test-savegame(state)s that are either won or lost
		testSaveGamesLost.put("" +
				"//{mobs}\n" +
				"//@;1;1;n;50;75;50;50;10\n" +
				"//@;2;1;n;50;75;50;50;0\n" +
				"//{gamedata}\n" +
				"//activeteam:@\n" +
				"//playedrounds:2\n" +
				"//maxrounds:5", true);
		testSaveGamesLost.put("" +
				"//{mobs}\n" +
				"//@;1;1;n;50;75;50;50;10\n" +
				"//Z;2;1;n;0;75;50;0;0\n" +
				"//{gamedata}\n" +
				"//activeteam:@\n" +
				"//playedrounds:2\n" +
				"//maxrounds:5", true);
		testSaveGamesLost.put("" +
				"//{mobs}\n" +
				"//@;1;1;n;50;75;50;50;10\n" +
				"//{gamedata}\n" +
				"//activeteam:@\n" +
				"//playedrounds:5\n" +
				"//maxrounds:5", true);
		testSaveGamesLost.put("" +
				"//{mobs}\n" +
				"//@;1;1;n;50;75;50;50;10\n" +
				"//{gamedata}\n" +
				"//activeteam:@\n" +
				"//playedrounds:6\n" +
				"//maxrounds:5", true);
		testSaveGamesLost.put("" +
				"//{mobs}\n" +
				"//Z;1;1;n;50;75;50;0;0\n" +
				"//{gamedata}\n" +
				"//activeteam:@\n" +
				"//playedrounds:1\n" +
				"//maxrounds:5", false);
		testSaveGamesLost.put("" +
				"//{mobs}\n" +
				"//Z;1;1;n;50;75;50;0;0\n" +
				"//{gamedata}\n" +
				"//activeteam:@\n" +
				"//playedrounds:6\n" +
				"//maxrounds:5", false);
		testSaveGamesLost.put("" +
				"//{mobs}\n" +
				"//@;1;1;n;0;75;50;50;10\n" +
				"//{gamedata}\n" +
				"//activeteam:@\n" +
				"//playedrounds:1\n" +
				"//maxrounds:5", false);
		testSaveGamesLost.put("" +
				"//{gamedata}\n" +
				"//activeteam:@\n" +
				"//playedrounds:1\n" +
				"//maxrounds:5", false);

		// a level is either won or lost, no "in between" in this testcase
		for (String level : testSaveGamesLost.keySet()) {
			testAdapter.loadLevelFromString(testSaveGameLevel + level);
			if(testSaveGamesLost.get(level))
			{			
				assertTrue("Your implementation identified a won level not correctly "
					+ "\n" + level, 
					Boolean.valueOf(testAdapter.isWon()));
			}
			else
			{			
				assertTrue("Your implementation identified a lost level not correctly "
					+ "\n" + level, 
					Boolean.valueOf(testAdapter.isLost()));
			}
		}
	}

	/**
	 * Test method for {@link de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel1#loadLevelFromString()}.
	 */
	@Test
	public final void testSavegameTurnsLeft() {
		
		testAdapter.loadLevelFromString(testSaveGameLevel +
				"//{mobs}\n" +
				"//@;1;1;n;50;75;50;50;10\n" +
				"//@;2;1;n;50;75;50;50;0\n" +
				"//Z;2;2;n;50;75;50;0;0\n" +
				"//{gamedata}\n" +
				"//activeteam:@\n" +
				"//playedrounds:5\n" +
				"//maxrounds:5");
		assertEquals("There should be 0 turns left", 0, testAdapter.turnsLeft());
		
		testAdapter.loadLevelFromString(testSaveGameLevel +
				"//{mobs}\n" +
				"//@;1;1;n;50;75;50;50;10\n" +
				"//@;2;1;n;50;75;50;50;0\n" +
				"//Z;2;2;n;50;75;50;0;0\n" +
				"//{gamedata}\n" +
				"//activeteam:@\n" +
				"//playedrounds:6\n" +
				"//maxrounds:5");
		assertEquals("There should be 0 turns left", 0, testAdapter.turnsLeft());
		
		testAdapter.loadLevelFromString(testSaveGameLevel +
				"//{mobs}\n" +
				"//@;1;1;n;50;75;50;50;10\n" +
				"//@;2;1;n;50;75;50;50;0\n" +
				"//Z;2;2;n;50;75;50;0;0\n" +
				"//{gamedata}\n" +
				"//activeteam:@\n" +
				"//playedrounds:42\n" +
				"//maxrounds:5");
		assertEquals("There should be 0 turns left", 0, testAdapter.turnsLeft());
		
		String loadedSavegame = testSaveGameLevel +
				"//{mobs}\n" +
				"//@;1;1;n;50;75;50;50;10\n" +
				"//@;2;1;n;50;75;50;0;0\n" +
				"//Z;2;2;n;50;75;50;0;0\n" +
				"//{gamedata}\n" +
				"//activeteam:@\n" +
				"//playedrounds:4\n" +
				"//maxrounds:5";
		
		// no actions should be possible when 0 turns are left
		testAdapter.loadLevelFromString(loadedSavegame);
		testAdapter.endTurn();
		
		// do some actions
		testAdapter.changeActivePlayer(1, 1);
		testAdapter.rotateActivePlayer(true);
		testAdapter.rotateActivePlayer(true);
		testAdapter.performActionForActivePlayer();
		
		testAdapter.performKIAction("2;2;r");
		testAdapter.performKIAction("2;2;f");
		
		// remove any additional info at the end of the savegame
		String returnedSavegame = testAdapter.returnGamestateAsSavegame();
		// replace doors-line if there is any and remove any additional info if there is any
		returnedSavegame = returnedSavegame.replaceFirst("(?m)//\\{doors\\}\n", "");
		returnedSavegame = returnedSavegame.replaceFirst("(?s)//maxrounds:5(.*)$", "//maxrounds:5");
		
		assertEquals("There are no turns left, so the actions should not have changed the savegame",
				loadedSavegame.replaceAll("playedrounds:4", "playedrounds:5"), returnedSavegame);
		
	}
}
